package seabattle.field;

import seabattle.ship.Coordinates;
import seabattle.ship.Ship;

import java.util.Arrays;
import java.util.LinkedList;

public class BattleField implements Field, FieldEditable {
	public static final int SIZE = 10;
	private boolean visible = true;
	private Cell[][] field;
	private LinkedList<Ship> ships;

	public BattleField() {
		field = new Cell[SIZE][SIZE];
		ships = new LinkedList<Ship>();
		for (Cell column[] : field) {
			Arrays.fill(column, Cell.EMPTY);
		}
	}

	public Message catchingShot(Coordinates disposal) {
		Ship ship = lookingShipByDisposal(disposal);
		if (ship == null) {
			return markShot(disposal.getX(), disposal.getY());
		}
		ship.destroySpecifiedDeck(disposal);
		markShot(disposal.getX(), disposal.getY());
		if (ship.amountAliveDecks() < 1) {
			drownShip(ship);
		}
		return Message.HIT;
	}

	private Ship lookingShipByDisposal(Coordinates disposal) {
		for (Ship ship : ships) {
			if (ship.isItYoursDeck(disposal)) {
				return ship;
			}
		}
		return null;
	}

	private Message markShot(int x, int y) {
		if (field[x][y] == Cell.SHIP) {
			field[x][y] = Cell.HIT;
			return Message.HIT;
		}
		if (field[x][y] == Cell.EMPTY) {
			field[x][y] = Cell.SHOT;
			return Message.MISS;
		}
		if (field[x][y] == Cell.SHOT) {
			return Message.AGAIN;
		}
		if (field[x][y] == Cell.HIT) {
			return Message.AGAIN;
		}
		return Message.ERR;
	}

	private void drownShip(Ship ship) {
		int x = ship.getDisposal().getX();
		int y = ship.getDisposal().getY();
		for (int index = 0; index < ship.getLength(); index++) {
			if (ship.getDirection().isVertical()) {
				drownDeck(x, y + index);
			} else {
				drownDeck(x + index, y);
			}
		}
	}

	private void drownDeck(int x, int y) {
		for (int deltaX = x - 1; deltaX < x + 2; deltaX++) {
			if ((deltaX < 0) || (deltaX > SIZE - 1)) {
				continue;
			}
			for (int deltaY = y - 1; deltaY < y + 2; deltaY++) {
				if ((deltaY < 0) || (deltaY > SIZE - 1)) {
					continue;
				}
				if (field[deltaX][deltaY] == Cell.EMPTY) {
					field[deltaX][deltaY] = Cell.SHOT;
				}
			}
		}
	}

	public boolean checkAliveShips() {
		for (Ship ship : ships) {
			if (ship.amountAliveDecks() != 0) {
				return true;
			}
		}
		return false;
	}

	public Cell[] getColumn(int row) {
		Cell[] column = new Cell[SIZE];
		for (int index = 0; index < SIZE; index++) {
			column[index] = field[index][row];
		}
		return column;
	}

	public boolean getVisible() {
		return visible;
	}

	public void setVisible(boolean visible) {
		this.visible = visible;
	}

	public Cell getCell(int x, int y) {
		return field[x][y];
	}

	public void addShip(Ship ship) {
		ships.add(ship);
		drawShipsOnField(ship);
	}

	private void drawShipsOnField(Ship ship) {
		int x = ship.getDisposal().getX();
		int y = ship.getDisposal().getY();
		for (int index = 0; index < ship.getLength(); index++) {
			if (ship.getDirection().isVertical()) {
				field[x][y + index] = Cell.SHIP;
			} else {
				field[x + index][y] = Cell.SHIP;
			}
		}
	}
}